package com.chentongwei.interceptor;

import com.alibaba.fastjson.JSON;
import com.chentongwei.entity.Result;
import com.chentongwei.enums.IBaseEnum;
import com.chentongwei.enums.ResponseStatusEnum;
import com.chentongwei.strategy.ExceptionStrategy;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @author TongWei.Chen 2018-03-01 17:03
 * @Description: 统一异常处理器
 */
@Order(-1000)
public class ExceptionResolver implements HandlerExceptionResolver {
    /**
     * 异常日志
     */
    private static final Logger LOG = LogManager.getLogger("exceptionLog");

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
        Result result = new Result();

        if (e instanceof ExceptionStrategy) {
            ExceptionStrategy exceptionStrategy = (ExceptionStrategy) e;
            IBaseEnum baseEnum = exceptionStrategy.resolverException();
            addResult(result, baseEnum, baseEnum.getMsg());
        } else if (e instanceof BindException) {
            resolverBindException(e, result);
        } else {
            resolverOtherException(e, result);
        }
        LOG.error("程序出现异常：" + result.getResult(), e);

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Cache-Control", "no-cache, must-revalidate");
        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException ex) {
            LOG.error("与客户端通讯异常：" + ex.getMessage(), ex);
        }
        return new ModelAndView();
    }

    /**
     * 处理参数绑定异常
     */
    private void resolverBindException(Throwable e, Result result) {
        BindException be = (BindException) e;
        List<FieldError> errorList = be.getBindingResult().getFieldErrors();
        StringBuilder sb = new StringBuilder();
        for (int i = 0, size = errorList.size(); i < size; i ++) {
            FieldError error = errorList.get(i);
            sb.append(error.getDefaultMessage());
            if (size > 1 && i != size - 1) {
                sb.append("并且");
            }
        }
        addResult(result, ResponseStatusEnum.PARAM_ERROR, sb.toString());
    }

    /**
     * 处理其他异常
     */
    private void resolverOtherException(final Throwable e, Result result) {
        addResult(result, ResponseStatusEnum.FAILED, e.getMessage());
    }

    /**
     * 封装code和msg
     */
    private final void addResult(Result result, final IBaseEnum baseEnum, final Object obj) {
        result.setCode(baseEnum.getCode());
        result.setMsg(baseEnum.getMsg());
        result.setResult(obj);
    }
}
